package comandos;

import model.Usuario;
import protocol.MensajeComando;
import server.ClienteHilo;
import server.Servidor;
import server.services.TatetiService;
import server.tateti.Jugador;
import server.tateti.Tateti;

/**
 * Esta clase sera el interprete de los comandos para el juego de tateti Es
 * intermediaria entre los clientes y el juego propiamente dicho
 * 
 */
public class ProtocoloTateti implements ComandoServidor {
	// Estas constantes representan la accion que se hara sobre el tateti
	private static final String TATETI = "tateti";
	private static final String INICIAR_JUEGO = "IniciarJuego";
	private static final String INVITACION = "Invitacion";
	private static final String RESPUESTA_INVITACION = "RespuestaInvitacion";
	private static final String MARCAR = "Marcar";
	private static final String REVANCHA = "Revancha";
	private static final String ABANDONAR = "Abandonar";
	private static final String TURNO = "Turno";
	private static final String GANADOR = "Ganador";

	private static ProtocoloTateti instance;
	private TatetiService service;
	
	
	private ProtocoloTateti() {
		service = TatetiService.getInstance();
		service.setProtocolo(this);
	}
	
	public static ProtocoloTateti getInstance() {
		if(instance == null)
			instance = new ProtocoloTateti();
		return instance;
	}

	/**
	 * Ejecuta una accion segun lo que reciba del cliente
	 */
	public void ejecutar(ClienteHilo cliente) {
		try {
			// Recibo la accion que se quiere ejecutar
			MensajeComando u = (MensajeComando) cliente.getInput().readObject();
			String accion = u.getMensaje();

			// Ejecuto la accion
			if (INICIAR_JUEGO.equals(accion)) {
				this.iniciarTateti(cliente);
			} else if (RESPUESTA_INVITACION.equals(accion)) {
				this.respuestaInvitacion(cliente);
			} else if (MARCAR.equals(accion)) {
				this.marcar(cliente);
			} else if (REVANCHA.equals(accion)) {
				this.revancha(cliente);
			} else if (ABANDONAR.equals(accion)) {
				this.abandonar(cliente);
			}

		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Problema al ejecutar el comando");
		}

	}

	// ****************************************************************************
	// Mensajes del cliente hacia el servidor
	// ****************************************************************************
	/**
	 * Ejecutada cuando un cliente quiere iniciar una idPartida de tateti
	 * 
	 * @param cliente
	 * @throws Exception
	 */
	private void iniciarTateti(ClienteHilo cliente) throws Exception {
		Usuario invitador = cliente.getUsuario();
		Usuario invitado = (Usuario) cliente.getInput().readObject();
		service.crearPartida(invitador, invitado);
	}

	/**
	 * Respuesta del cliente a una invitacion de jugar
	 * 
	 * @param cliente
	 * @throws Exception
	 */
	private void respuestaInvitacion(ClienteHilo cliente) throws Exception {
		Usuario usuario = cliente.getUsuario();
		Integer idPartida = (Integer) cliente.getInput().readObject();
		Boolean respuesta = (Boolean) cliente.getInput().readObject();
		service.responderInvitacion(idPartida, usuario, respuesta);
	}

	/**
	 * Solicitud de un cliente para marcar en determinada posicion
	 * 
	 * @param cliente
	 * @throws Exception
	 */
	private void marcar(ClienteHilo cliente) throws Exception {
		Usuario usuario = cliente.getUsuario();
		Integer idPartida = (Integer) cliente.getInput().readObject();
		Integer posicion = (Integer) cliente.getInput().readObject();
		service.marcar(idPartida, usuario, posicion);
	}

	/**
	 * Solicitud de revancha de un usuario
	 * 
	 * @param cliente
	 * @throws Exception
	 */
	private void revancha(ClienteHilo cliente) throws Exception {
		Usuario usuario = cliente.getUsuario();
		Integer idPartida = (Integer) cliente.getInput().readObject();
		service.revancha(idPartida, usuario);
	}

	/**
	 * Solicitud de un usuario de abandonar la idPartida
	 * 
	 * @param cliente
	 * @throws Exception
	 */
	private void abandonar(ClienteHilo cliente) throws Exception {
		Usuario usuario = cliente.getUsuario();
		Integer idPartida = (Integer) cliente.getInput().readObject();
		service.abandonar(idPartida, usuario);
	}

	// ****************************************************************************
	// Mensajes del servidor hacia el cliente
	// ****************************************************************************
	/**
	 * Notifica al usuario que lo invitaron a jugar tateti
	 * 
	 * @param cliente
	 * @param idPartida
	 * @param invitador
	 * @throws Exception
	 */
	public void invitar(Usuario usuario, Integer idPartida, Usuario invitador) throws Exception {
		ClienteHilo cliente = Servidor.getClienteHilo(usuario);
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(TATETI, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(INVITACION, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(idPartida);
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(invitador);
		cliente.getOutput().flush();
	}

	/**
	 * Notifica al usuario el comienzo de una idPartida de tateti
	 * 
	 * @param cliente
	 * @throws Exception
	 */
	public void iniciarTateti(Usuario usuario, Tateti partida)
			throws Exception {
		ClienteHilo cliente = Servidor.getClienteHilo(usuario);
		cliente.getOutput().writeObject(new MensajeComando(TATETI, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(INICIAR_JUEGO, 0));

		cliente.getOutput().writeObject(partida.getId());
		cliente.getOutput().writeObject(partida.getJugadores()[Tateti.J1].getUsuario());
		cliente.getOutput().writeObject(partida.getJugadores()[Tateti.J2].getUsuario());
	}

	/**
	 * Indica al usuario de quien es el turno de jugar
	 * 
	 * @param cliente
	 * @param idPartida
	 * @param usuario
	 * @throws Exception
	 */
	public void turno(Usuario u, Integer idPartida, Jugador jugador)
			throws Exception {
		ClienteHilo cliente = Servidor.getClienteHilo(u);
		cliente.getOutput().writeObject(new MensajeComando(TATETI, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(TURNO, 0));

		cliente.getOutput().writeObject(idPartida);
		cliente.getOutput().writeObject(jugador.getId());
	}

	/**
	 * Indica a un usuario que una posicion fue marcada
	 * 
	 * @param cliente
	 * @param idPartida
	 * @param usuario
	 * @param posicion
	 * @throws Exception
	 */
	public void posicionMarcada(Usuario u, Integer idPartida,
			Jugador jugador, Integer posicion) throws Exception {
		ClienteHilo cliente = Servidor.getClienteHilo(u);
		cliente.getOutput().writeObject(new MensajeComando(TATETI, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(MARCAR, 0));

		cliente.getOutput().writeObject(idPartida);
		cliente.getOutput().writeObject(jugador.getId());
		cliente.getOutput().writeObject(posicion);
	}

	/**
	 * Notifica a un cliente el ganador de una idPartida de tateti
	 * 
	 * @param cliente
	 * @param idPartida
	 * @param ganador
	 * @throws Exception
	 */
	public void notificarGanador(Usuario usuario, Integer idPartida,
			Integer idGanador) throws Exception {
		ClienteHilo cliente = Servidor.getClienteHilo(usuario);
		cliente.getOutput().writeObject(new MensajeComando(TATETI, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(GANADOR, 0));

		cliente.getOutput().writeObject(idPartida);
		cliente.getOutput().writeObject(idGanador);
	}

	/**
	 * Notifica a un cliente que el usuario abandono la idPartida
	 * 
	 * @param cliente
	 * @param idPartida
	 * @param usuario
	 * @throws Exception
	 */
	public void abandono(Usuario u, Integer idPartida, Jugador jugador)
			throws Exception {
		ClienteHilo cliente = Servidor.getClienteHilo(u);
		cliente.getOutput().writeObject(new MensajeComando(TATETI, 0));
		cliente.getOutput().flush();
		cliente.getOutput().writeObject(new MensajeComando(ABANDONAR, 0));

		cliente.getOutput().writeObject(idPartida);
		cliente.getOutput().writeObject(jugador.getId());
	}
}

